#!/usr/bin/python
# -*- coding: utf-8 -*-

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import traceback
import time
import datetime
import logging
from xmppbot import Bots, Account
from dicts import Dictionaries, ConnectionError as DictsConnectionError
from ConfigParser import RawConfigParser, NoOptionError, NoSectionError

__version__ = '0.1'
not_found = 'No translation found'
homepage = 'http://code.google.com/p/dictbot/'

# Generate simple tranlsation callback.
def generate_callback(dicts):
    def message_recieved(word):
        global translations
        translations += 1
        reply = ''
        for d in dicts:
            translation = d.translate(word)
            if not translation is None:
                reply+=translation+'\n'
        if reply != '':
            return reply
        else:
            return not_found
    return message_recieved

# def save_error(error):
#    errors+=1
#    error_log.append((time.time(), error))
#    if len(error_log)>10:
#        error_log=error_log[-10:]

# return statistics
def stat():
    global start_time, translations, commands
    s = ''
    s += 'Started: %s %s\n' % (time.ctime(start_time), 
                               time.tzname[time.daylight])
    # Find time delta.
    dt = datetime.timedelta(seconds=time.time() - start_time)
    s += 'Uptime: %s\n' % str(dt)
    s += 'Translations: %s\n' % str(translations)
    s += 'Commands: %s' % str(commands)
    return s

# Main bot logic. All commands.
def bot_logic(cmd):
    global translations, commands
    short_help = 'Try "!help" for help.'
    no_dict = 'Dictionary not found.'
    unknown_cmd = 'Unknown command.'
    connection_failed = 'Can\'t connect to a server. Sorry.'
    long_help = '!list - dictionaries list\n' \
        '!stat - show statistics\n' \
        '!help - this help\n' \
        'syntax: dictionary word\n' \
        'homepage: %s' % homepage
    # Special command
    if cmd.startswith('!'):
        commands+=1
        cmd=cmd[1:].lower()
        if cmd == 'help':
            return long_help
        elif cmd == 'list':
            #Return formatted dictionaries list in form "name: dsc".
            return '\n'.join(
                map(lambda d: d + ': '+ dicts[d].dsc, sorted(dicts.keys())))
        elif cmd == 'stat':
            return stat()
        else:
            return unknown_cmd
    #Normal request in form "dictionary word".
    try:
        translations+=1
        dict_id, word = cmd.split(' ', 1)
        reply = dicts[dict_id].translate(word)
        if reply is None:
            return not_found
        else:
            return reply
    #Oops. No space in request.
    except ValueError:
        return short_help
    #Unknown dictionary.
    except KeyError:
        return no_dict
    #Connection error.
    except DictsConnectionError:
        #save_error(msg)
        return connection_failed
    return repr(dicts.keys())

def pairs_to_dict(l):
    d={}
    for k, v in l:
        d[k] = v
    return d

# Read config and start.
def main():
    global dicts
    global simple_naming
    global start_time, translations, commands
    #set start time
    start_time=time.time()
    translations=0
    commands=0
    if len(sys.argv) < 1:
        print "Usage: %s config" % sys.argv[0]
        sys.exit(1)
    accounts = []
    config = RawConfigParser()
    config.read(sys.argv[1])
    # Tune logging
    if config.has_option('setup', 'logfile'):
        logging.basicConfig(filename=config.get('setup', 'logfile'),
                            level=logging.DEBUG,
                            format='%(asctime)s %(levelname)s %(message)s')
    else:
        logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s %(levelname)s %(message)s')
    simple_naming = False
    if config.has_option('setup', 'naming'):
        if config.get('setup','naming')=='simple':
            simple_naming= True
    dictionaries = pairs_to_dict(config.items('dictionaries'))
    #print dictionaries
    try:
        aliases = pairs_to_dict(config.items('aliases'))
    except NoSectionError:
        aliases = {}
    try:
        descriptions = pairs_to_dict(config.items('descriptions'))
    except NoSectionError:
        descriptions = {}
    dicts = Dictionaries(dictionaries,
                         aliases,
                         descriptions,
                         simple_naming)
    jids = pairs_to_dict(config.items('jid'))
    for jid in jids:
        login, server = jid.split('@', 1)
        password = config.get('passwords', jid)
        if jids[jid] == 'all':
            callback = bot_logic
        else:
            callback = generate_callback(
                [dicts[d_name] for d_name in jids[jid].split(',')])
        account = Account(login + '@' + server, password, callback)
        accounts.append(account)
    # Infinity cycle. Reconnect on error.
    while True:
        try:
            logging.debug('Creating bot.')
            bots=Bots(accounts, 'dictbot', __version__)
            logging.debug('Entering answer loop')
            bots.run()
        #Somebody pressed C-c.
        except KeyboardInterrupt, e:
            raise e
        except:
            ei = sys.exc_info()
            logging.warning(''.join(traceback.format_exception(
                                    ei[0], ei[1], ei[2], None)))
            logging.info("Sleeping 5 seconds.")
            time.sleep(5)
            logging.warning("Restarting.")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        logging.info("C-c pressed. Exiting.")
        sys.exit(0)
